﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace XFGameFramework.BuffSystem
{

    public class BuffManager
    {
        #region 字段

        private static List<IAddableBuff> addables = new List<IAddableBuff>();

        private static Dictionary<IAddableBuff, Dictionary<int, EffectData>> addable_effects = new Dictionary<IAddableBuff, Dictionary<int, EffectData>>();

        #endregion

        #region Config

        private static List<BuffsConfig> configs = new List<BuffsConfig>();

        /// <summary>
        /// 添加Buff配表
        /// </summary>
        /// <param name="buffConfig">Buff配置</param>
        /// <exception cref="Exception">ID重复</exception>
        public static void AddConfig(BuffsConfig buffConfig)
        {
            if (configs.Contains(buffConfig))
            {
                Debug.LogWarningFormat("已添加Buff配置,请勿重复添加!");
                return;
            }

            foreach (var buff in buffConfig.buffs)
            {
                foreach (var config in configs)
                {
                    if (config.GetBuffData(buff.buff_id) == null)
                        continue;

                    StringBuilder builder = new StringBuilder();
                    builder.Append("检测到Buff id重复,");
                    builder.Append("配置:").Append(buffConfig.name);
                    builder.Append("Buff:").Append(buff.buff_id).Append(buff.buff_name);
                    builder.Append("配置:").Append(config.name);
                    builder.Append("Buff:").Append(buff.buff_id).Append(config.GetBuffData(buff.buff_id).buff_name);

                    throw new Exception(builder.ToString());
                }
            }

            configs.Add(buffConfig);
        }

        /// <summary>
        /// 移除Buff配表
        /// </summary>
        /// <param name="buffConfig"></param>
        public static void RemoveConfig(BuffsConfig buffConfig)
        {
            if (configs.Contains(buffConfig))
            {
                configs.Remove(buffConfig);
            }
        }

        /// <summary>
        /// 查询配表
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static BuffsConfig GetConfig(string name)
        {
            foreach (var item in configs)
            {
                if (item.name.Equals(name)) return item;
            }

            return null;
        }

        #endregion
         
        static BuffManager() 
        {
            UpdateManager.RemoveUpdateEvent(Update);
            UpdateManager.RemoveFixedUpdateEvent(FixedUpdate);
            UpdateManager.RemoveLateUpdateEvent(LateUpdate);

            UpdateManager.AddUpdateEvent(Update);
            UpdateManager.AddFixedUpdateEvent(FixedUpdate);
            UpdateManager.AddLateUpdateEvent(LateUpdate);

        }


        #region 方法


        // 查询Buff的配置信息 
        private static BuffConfigData GetBuffData(int buff_id)
        {
            foreach (var item in configs)
            {
                BuffConfigData data = item.GetBuffData(buff_id);
                if (data != null)
                    return data;
            }

            return null;
        }

        /// <summary>
        /// 添加Buff
        /// </summary>
        /// <param name="addable"></param>
        /// <param name="buff_id"></param>
        /// <exception cref="Exception"></exception>
        public static BuffBase AddBuff(IAddableBuff addable, int buff_id, object userData = null)
        {
            if (addable == null) return null;

            BuffConfigData buffData = GetBuffData(buff_id);

            if (buffData == null)
                throw new Exception(string.Format("未查询到Buff数据,id:{0}", buff_id));
            return AddBuff(addable, buff_id, buffData.duration, userData);
        }

        public static BuffBase AddBuff(IAddableBuff addable, int buff_id, float duration, object userData = null)
        {
            // 判断目标是否为空
            if (addable == null) return null;

            // 判断目标是否能够添加这个buff
            if (!addable.IsCanAdd(buff_id)) return null;

            if (addable is View)
            {
                View view = addable as View;
                if (!view || !view.gameObject.activeInHierarchy)
                {
                    Debug.LogWarningFormat("非活跃状态的游戏物体:{0}不能添加Buff!", view.name);
                    return null;
                }
            }

            // 获取到类型 

            BuffConfigData buffData = GetBuffData(buff_id);

            if (buffData == null)
                throw new Exception(string.Format("未查询到Buff数据,id:{0}", buff_id));

            Type type = AssemblyTools.GetType(buffData.buff_class_full_name);

            if (type == null)
                type = typeof(BuffBase); // 如果没有查询到使用基类

            BuffBase buff = ClassObjectPoolManager.Load(type) as BuffBase;

            if (buff == null)
                throw new Exception("buff创建失败!");

            buff.BuffData = buffData;
            buff.ResetData();
            buff.Duration = duration;
            buff.userData = userData;
            buff.Owner = addable;

            // 如果该buff不能添加 直接return
            if (!buff.IsCanAdd())
            {
                ClassObjectPoolManager.Unload(buff);
                return null;
            }

            // 判断Buff模式
            if (buff.BuffData.mode == BuffMode.Single)
            {
                // 如果是不可叠加的Buff 需要把之前添加的buff移除掉
                BuffBase last = null;
                foreach (var item in addable.Buffs)
                {
                    if (item.BuffData.buff_id == buff_id)
                    {
                        last = item;
                        break;
                    }
                }
                if (last != null)
                {
                    // 移除 
                    RemoveBuff(addable, last);
                }
            }

            if (!addables.Contains(addable))
                addables.Add(addable);


            addable.Buffs.Add(buff);
            // 更新效果缓存
            UpdateEffects(addable);
            buff.OnAdd(); 
            addable.OnAddBuff(buff);

            return buff;
        }

        /// <summary>
        /// 添加一组Buff
        /// </summary>
        /// <param name="addable"></param>
        /// <param name="buffs"></param>
        public static void AddBuff(IAddableBuff addable, IList<int> buffs, object userData = null)
        {
            if (addable == null || buffs == null) return;
            foreach (var item in buffs)
            {
                AddBuff(addable, item, userData);
            }
        }


        public static void AddBuff(IAddableBuff addable, IList<int> buffs,float duration, object userData = null)
        {
            if (addable == null || buffs == null) return;
            foreach (var item in buffs)
            {
                AddBuff(addable, item, duration,userData);
            }
        }

        /// <summary>
        /// 移除Buff
        /// </summary>
        /// <param name="addable"></param>
        /// <param name="buff"></param>
        public static void RemoveBuff(IAddableBuff addable, BuffBase buff)
        {

            if (addable == null || buff == null)
                return;

            if (!addable.Buffs.Contains(buff))
                return;

            addable.Buffs.Remove(buff);
            // 更新效果缓存
            UpdateEffects(addable);
            buff.OnRemove();
            addable.OnRemoveBuff(buff);

            

            if (addable.Buffs.Count == 0)
                addables.Remove(addable);
            ClassObjectPoolManager.Unload(buff);


        }

        /// <summary>
        /// 移除一组buff
        /// </summary>
        /// <param name="addable"></param>
        /// <param name="buffs"></param>
        public static void RemoveBuff(IAddableBuff addable, IList<BuffBase> buffs)
        {
            if (addable == null) return;

            if (buffs == addable.Buffs)
            {
                RemoveBuff(addable);
                return;
            }

            foreach (var item in buffs)
            {
                RemoveBuff(addable, item);
            }
        }

        /// <summary>
        /// 移除所有Buff
        /// </summary>
        /// <param name="addable"></param>
        public static void RemoveBuff(IAddableBuff addable)
        {
            if (!addables.Contains(addable))
                return;

            if (addable == null || addable.Buffs == null || addable.Buffs.Count == 0)
            {
                addables.Remove(addable);
                return;
            }

            for (int i = addable.Buffs.Count - 1; i >= 0; i--)
            {
                RemoveBuff(addable, addable.Buffs[i]);
            }
        }


        /// <summary>
        /// 移除某个类型的所有Buff
        /// </summary>
        /// <param name="addable"></param>
        /// <param name="type"></param>
        public static void RemoveBuff(IAddableBuff addable, Type type)
        {

            if (addable == null) return;

            for (int i = addable.Buffs.Count - 1; i >= 0; i--)
            {
                if (addable.Buffs[i].GetType() != type)
                    continue;

                RemoveBuff(addable, addable.Buffs[i]);
            }
        }

        /// <summary>
        /// 移除Buff(根据id)
        /// </summary>
        /// <param name="addable"></param>
        /// <param name="buff_id"></param>
        public static void RemoveBuff(IAddableBuff addable, int buff_id)
        {
            if (addable == null) return;

            for (int i = addable.Buffs.Count - 1; i >= 0; i--)
            {
                if (addable.Buffs[i].BuffData.buff_id != buff_id)
                    continue;

                RemoveBuff(addable, addable.Buffs[i]);
            }
        }


        /// <summary>
        /// 移除指定类型的所有Buff
        /// </summary> 
        public static void RemoveBuff<T>(IAddableBuff addable) where T : BuffBase
        {
            if (addable == null) return;

            for (int i = addable.Buffs.Count - 1; i >= 0; i--)
            {
                if (!(addable.Buffs[i] is T))
                    continue;

                RemoveBuff(addable, addable.Buffs[i]);
            }
        }


        /// <summary>
        /// 查询效果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="addable"></param>
        /// <returns></returns>
        public static void GetEffects<T>(IAddableBuff addable, List<T> results) where T : EffectData
        {
            if (results == null)
                throw new Exception("参数 results 不能为空!");

            results.Clear();

            if (addable == null) return;

            foreach (var buff in addable.Buffs)
            {
                foreach (var effect in buff.BuffData.effects)
                {
                    if (!(effect is T)) continue;
                    T effectInfo = effect as T;
                    results.Add(effectInfo);
                }
            }
        }

        /// <summary>
        /// 查询效果(指定id查询)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="addble"></param>
        /// <param name="result"></param>
        /// <param name="effect_name"></param>
        public static void GetEffects<T>(IAddableBuff addable, List<T> results, int id) where T : EffectData
        {
            if (results == null)
                throw new Exception("参数 results 不能为空!");

            results.Clear();

            if (addable == null) return;

            foreach (var buff in addable.Buffs)
            {
                foreach (var effect in buff.BuffData.effects)
                {
                    if (!(effect is T) || effect.id != id)
                        continue;
                    T effectInfo = effect as T;
                    results.Add(effectInfo);
                }
            }
        }

        /// <summary>
        /// 根据类型查询效果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="addable"></param>
        /// <param name="results"></param>
        /// <param name="type"></param>
        /// <exception cref="Exception">results 不能为空!</exception>
        public static void GetEffectsByType<T>(IAddableBuff addable, List<T> results, int type) where T : EffectData
        {
            if (results == null)
                throw new Exception("参数 results 不能为空!");

            results.Clear();

            if (addable == null) return;


            foreach (var buff in addable.Buffs)
            {
                foreach (var effect in buff.BuffData.effects)
                {
                    if (!(effect is T) || effect.type != type)
                        continue;
                    T effectInfo = effect as T;
                    results.Add(effectInfo);
                }
            }
        }

        // Update 相关 

        private static void Update()
        {

            for (int i = 0; i < addables.Count; i++)
            {

                if (i >= addables.Count)
                    continue;

                IAddableBuff addable = addables[i];

                // 如果已经被销毁了 就直接移除
                if (CheckDestroyBuff(addable))
                {
                    i--;
                    continue;
                }
                // 如果是disable状态 不需要执行update逻辑 直接跳过就行
                if (IsDisableBuff(addable)) continue;


                for (int j = 0; j < addable.Buffs.Count; j++)
                {

                    BuffBase buff = addable.Buffs[j];
                    buff.Update();
                    if (buff.Progress >= 1)
                    {
                        RemoveBuff(addable, buff);
                        j--;
                    }
                }

            }

        }

        private static void FixedUpdate()
        {

            for (int i = 0; i < addables.Count; i++)
            {

                if (i >= addables.Count)
                    continue;

                IAddableBuff addable = addables[i];

                // 如果已经被销毁了 就直接移除
                if (CheckDestroyBuff(addable))
                {
                    i--;
                    continue;
                }
                // 如果是disable状态 不需要执行update逻辑 直接跳过就行
                if (IsDisableBuff(addable)) continue;

                for (int j = 0; j < addable.Buffs.Count; j++)
                {
                    BuffBase buff = addable.Buffs[j];
                    buff.FixedUpdate();
                }
            }

        }

        private static void LateUpdate()
        {
            for (int i = 0; i < addables.Count; i++)
            {

                if (i >= addables.Count)
                    continue;

                IAddableBuff addable = addables[i];

                // 如果已经被销毁了 就直接移除
                if (CheckDestroyBuff(addable))
                {
                    i--;
                    continue;
                }
                // 如果是disable状态 不需要执行update逻辑 直接跳过就行
                if (IsDisableBuff(addable)) continue;

                for (int j = 0; j < addable.Buffs.Count; j++)
                {
                    BuffBase buff = addable.Buffs[j];
                    buff.OnLateUpdate();
                }
            }
        }


        private static bool CheckDestroyBuff(IAddableBuff addable)
        {
            bool destroy = IsDestroyBuff(addable);

            if (destroy)
            {
                RemoveBuff(addable);
                addables.Remove(addable);
            }

            return destroy;
        }


        /// <summary>
        /// 判断buff是否被销毁
        /// </summary>
        private static bool IsDestroyBuff(IAddableBuff addable)
        {
            if (!(addable is UnityEngine.Object)) return false;
            UnityEngine.Object obj = addable as UnityEngine.Object;
            return !obj;
        }

        /// <summary>
        /// 判断buff是否被隐藏
        /// </summary>
        private static bool IsDisableBuff(IAddableBuff addable)
        {
            if (!(addable is Component)) return false;
            Component obj = addable as Component;
            return !obj.gameObject.activeInHierarchy;
        }

        private static void UpdateEffects(IAddableBuff addable)
        {
            if (!addable_effects.ContainsKey(addable)) 
                addable_effects.Add(addable, new Dictionary<int, EffectData>());

            addable_effects[addable].Clear();

            foreach (var item in addable.Buffs)
            {
                foreach (var effect in item.BuffData.effects)
                {
                    if (addable_effects[addable].ContainsKey(effect.id)) 
                        continue;
                    addable_effects[addable].Add(effect.id, effect);
                }
            }
        }

         
        /// <summary>
        /// 判断游戏物体是否有某个效果
        /// </summary>
        /// <param name="addable">游戏物体对象</param>
        /// <param name="effect_id">效果id</param>
        /// <returns></returns>
        public static bool IsContainEffect(IAddableBuff addable,int effect_id) 
        { 
            if (addable_effects.ContainsKey(addable))
                return addable_effects[addable].ContainsKey(effect_id);

            return false;
        }

        #endregion
    }

}